atspicontext: Implement GetRelationSet
authorMatthias Clasen <mclasen@redhat.com>
Sat, 10 Oct 2020 14:43:59 +0000 (10:43 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Mon, 12 Oct 2020 19:10:40 +0000 (15:10 -0400)
This translates relations as far as the match.

I'm not sure yet what we can do about the fact that
atspi expects relations to be bidirectional (ie have
label-for *and* labelled-by) while aria has only one
direction.

gtk/a11y/gtkatspicontext.c

index 32b85ffabd5661367f82a094e4239570aaed6c76..b7031a9a92659512d3553d6f8df41e121804bbd6 100644 (file)
@@ -180,6 +180,50 @@ collect_states (GtkAtSpiContext    *self,
   g_variant_builder_add (builder, "u", (guint32) (state >> 32));
 }
 
+static void
+collect_relations (GtkAtSpiContext *self,
+                   GVariantBuilder *builder)
+{
+  GtkATContext *ctx = GTK_AT_CONTEXT (self);
+  struct {
+    GtkAccessibleRelation r;
+    AtspiRelationType s;
+  } map[] = {
+    { GTK_ACCESSIBLE_RELATION_LABELLED_BY, ATSPI_RELATION_LABELLED_BY },
+    { GTK_ACCESSIBLE_RELATION_CONTROLS, ATSPI_RELATION_CONTROLLER_FOR },
+    { GTK_ACCESSIBLE_RELATION_DESCRIBED_BY, ATSPI_RELATION_DESCRIBED_BY },
+    { GTK_ACCESSIBLE_RELATION_FLOW_TO, ATSPI_RELATION_FLOWS_TO},
+  };
+  GtkAccessibleValue *value;
+  GList *list, *l;
+  GtkATContext *target_ctx;
+  const char *unique_name;
+  int i;
+
+  unique_name = g_dbus_connection_get_unique_name (self->connection);
+
+  for (i = 0; i < G_N_ELEMENTS (map); i++)
+    {
+      if (!gtk_at_context_has_accessible_relation (ctx, map[i].r))
+        continue;
+
+      GVariantBuilder b = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a(so)"));
+
+      value = gtk_at_context_get_accessible_relation (ctx, map[i].r);
+      list = gtk_reference_list_accessible_value_get (value);
+
+      for (l = list; l; l = l->next)
+        {
+          target_ctx = gtk_accessible_get_at_context (GTK_ACCESSIBLE (l->data));
+          g_variant_builder_add (&b, "(so)",
+                                 unique_name,
+                                 GTK_AT_SPI_CONTEXT (target_ctx)->context_path);
+        }
+
+      g_variant_builder_add (builder, "(ua(so))", map[i].s, &b);
+    }
+}
+
 static void
 handle_accessible_method (GDBusConnection       *connection,
                           const gchar           *sender,
@@ -324,6 +368,12 @@ handle_accessible_method (GDBusConnection       *connection,
 
       g_dbus_method_invocation_return_value (invocation, g_variant_new ("(i)", idx));
     }
+  else if (g_strcmp0 (method_name, "GetRelationSet") == 0)
+    {
+      GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a(ua(so))"));
+       collect_relations (self, &builder);
+      g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a(ua(so)))", &builder));
+    }
   else if (g_strcmp0 (method_name, "GetInterfaces") == 0)
     {
       GtkAccessible *accessible = gtk_at_context_get_accessible (GTK_AT_CONTEXT (self));